//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  SchedulerService.cs
//    
// Abstract:
//
//  The Scheduler service class. This is the main entry point for the service.
//  
//--

using System;
using System.Diagnostics;
using System.ServiceProcess;

using Microsoft.OfficeCommunicationsServer.Applications.Common;

namespace Microsoft.EnhancedReminders.Scheduler
{
    /// <summary>
    /// Scheduler service class.
    /// </summary>
    public sealed class SchedulerService : ServiceBase
    {
        // Actual scheduler
        private SchedulerManager _schedulerManager;

        // Proxy to the Dispatcher service(s)
        private DispatcherProxy _dispatcherProxy;

        // Collection of users
        private ExchangeUsers _exchangeUsers;

        // Message queue paths used to communicate with the Dispatcher(s)
        private const string _sendQueuePath = @".\Private$\" + Constants.SendQueueName;
        private const string _responseQueuePath = @".\Private$\EnhancedRemindersResponses";
        private const string _administrationQueuePath = @".\Private$\EnhancedRemindersAdministrationQueue";

        private delegate void StopAsyncDelegate();

        // The cut-off time period after which notifications will not be delivered to the Dispatcher
        internal static TimeSpan _sendCutoffTimePeriod = TimeSpan.FromMinutes(Helpers.GetSetting<int>(Constants.SendCutoffPeriodInMinutesSetting, 2));

        /// <summary>
        /// Starts the Scheduler. This method is invoked when the service starts.
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {
            // Initialize logging for the Scheduler
            EnhancedRemindersHelpers.InitializeLogging("Microsoft Enhanced Reminders Scheduler");

            OperationalLogs.LogServiceStartingInformation();
            
            try
            {
                // Initialize
                _dispatcherProxy = new DispatcherProxy(_sendQueuePath, _responseQueuePath, _administrationQueuePath, _sendCutoffTimePeriod);
                _exchangeUsers = new ExchangeUsers(_dispatcherProxy);
                _schedulerManager = new SchedulerManager(_exchangeUsers, _dispatcherProxy);

                // Find initial users
                Logger.WriteTraceInformation("Finding users...");
                _exchangeUsers.AddNewUsers();

                // Start receiving repsonses from the Dispatcher
                Logger.WriteTraceInformation("Starting to receive responses...");
                _dispatcherProxy.Open();

                // Start synchronizing the schedule with the data from each user's mailbox
                Logger.WriteTraceInformation("Synchronizing schedule with Exchange...");
                _exchangeUsers.Open();
            }
            catch (Exception ex)
            {
                OperationalLogs.LogServiceStartError(ex);
                throw;
            }

            OperationalLogs.LogServiceStartedInformation();
        }

        /// <summary>
        /// Stops the Scheduler. This method is invoked when the service stops.
        /// </summary>
        /// <remarks>
        /// This method waits for the SchedulerManager to shut down cleanly before exiting.
        /// </remarks>
        protected override void OnStop()
        {
            OperationalLogs.LogServiceStoppingInformation();

            StopAsyncDelegate stopAsyncDelegate = new StopAsyncDelegate(AsyncStop);

            IAsyncResult asyncResult = stopAsyncDelegate.BeginInvoke(null, null);

            // Get the shutdown timeout from the config file. Default to 20 seconds.
            int shutdownTimeout = Helpers.GetSetting<int>(Constants.ShutdownTimeoutInSecondsSetting, 20);

            // Wait for SchedulerManager to shutdown cleanly
            if (!asyncResult.AsyncWaitHandle.WaitOne(shutdownTimeout * 1000 /* Milliseconds */, false))
            {
                // If the shutdown takes too long, log a warning and then exit
                OperationalLogs.LogServiceShutdownTimeoutWarning(shutdownTimeout);
            }

            asyncResult.AsyncWaitHandle.Close();

            OperationalLogs.LogServiceStoppedInformation();
        }

        /// <summary>
        /// Stops the Scheduler.
        /// </summary>
        /// <remarks>
        /// This method is invoked on a spearate thread so that the overall shut down process can have a single timeout.
        /// </remarks>
        private void AsyncStop()
        {
            Debug.Assert(_schedulerManager != null, "_schedulerManager should not be null at shutdown");

            _schedulerManager.Dispose();
            _schedulerManager = null;

            _dispatcherProxy.Dispose();
            _dispatcherProxy = null;

            _exchangeUsers.Dispose();
            _exchangeUsers = null;
        }

    }
}
